#pragma once
#include "rpc_register.hpp"
#include "rpc_caller.hpp"
#include "requestor.hpp"
#include "../common/dispatcher.hpp"
#include "rpc_topic.hpp"
namespace BRpc
{
    namespace Client
    {
        // 注册客户端
        class RegisterClient
        {
        public:
            using ptr = std::shared_ptr<RegisterClient>;

        public:
            RegisterClient(const std::string &ip, int port)
                : _requestor(std::make_shared<Requestor>()), _register(std::make_shared<Register>(_requestor)), _dispatcher(std::make_shared<Dispatcher>())
            {
                // 先将requestor注册到dispatcher中
                auto reque_cb = std::bind(&Requestor::onMessage, _requestor.get(), std::placeholders::_1, std::placeholders::_2);
                _dispatcher->registerHandler<BaseMessage>(MType::RSP_SERVICE, reque_cb);
                // 再将dispatcher注册到服务器的回调函数
                auto dis_cb = std::bind(&Dispatcher::onMessage, _dispatcher.get(), std::placeholders::_1, std::placeholders::_2);
                _client = ClientFactory::create(ip, port);
                _client->setMessageCallback(dis_cb);
                _client->connect();
            }
            bool registerMethod(const std::string &method, Address &host) // 输出形参数host 用于获取服务主机
            {
                return _register->registerMethod(_client->connection(), method, host);
            }

        private:
            Requestor::ptr _requestor;
            Register::ptr _register;
            Dispatcher::ptr _dispatcher;
            BaseClient::ptr _client;
        };
        class DiscovererClient
        {
        public:
            using ptr = std::shared_ptr<DiscovererClient>;

        public:
            DiscovererClient(const std::string &ip, int port,Discoverer::offlineCb off_cb)
                : _requestor(std::make_shared<Requestor>()), _discoverer(std::make_shared<Discoverer>(_requestor,off_cb)),
                _dispatcher(std::make_shared<Dispatcher>())
            {
                // 先将requestor注册到dispatcher中
                auto req_cb = std::bind(&Requestor::onMessage, _requestor.get(), std::placeholders::_1, std::placeholders::_2);
                auto rsp_cb = std::bind(&Discoverer::onServiceRequest, _discoverer.get(), std::placeholders::_1, std::placeholders::_2); // 接收到上下线通知的处理
                _dispatcher->registerHandler<BaseMessage>(MType::RSP_SERVICE, req_cb);
                _dispatcher->registerHandler<ServiceRequest>(MType::RSP_SERVICE, rsp_cb); // 后边注意一下 什么时候会发送这个类型的请求
                // 再将dispatcher注册到服务器的回调函数
                auto dis_cb = std::bind(&Dispatcher::onMessage, _dispatcher.get(), std::placeholders::_1, std::placeholders::_2);
                _client = ClientFactory::create(ip, port);
                _client->setMessageCallback(dis_cb);
                _client->connect();
            }
            bool serviceDiscover(const std::string &method, Address &host)
            {
                return _discoverer->serviceDiscover(_client->connection(), method, host);
            }

        private:
            Requestor::ptr _requestor;
            Discoverer::ptr _discoverer;
            Dispatcher::ptr _dispatcher;
            BaseClient::ptr _client;
        };
        class RpcClient
        {
        public:
            using ptr = std::shared_ptr<RpcClient>;
            // 用于计算Address的哈希值
            struct AddressHash
            {
                size_t operator()(const Address &addr) const
                {
                    std::string str = addr.first + std::to_string(addr.second);
                    return std::hash<std::string>{}(str);
                }
            };

        public:
            // isDiscover用于判断是否进行服务发现 进行服务发现的话ip和port指向的是服务注册中心 不然就是服务提供者的服务器
            RpcClient(const bool isDiscover, const std::string ip,const  int port)
                : _requestor(std::make_shared<Requestor>()), _dispatcher(std::make_shared<Dispatcher>()),
                  _caller(std::make_shared<RpcCaller>(_requestor)), _isDiscover(isDiscover)
            {
                auto req_cb = std::bind(&Requestor::onMessage, _requestor.get(), std::placeholders::_1, std::placeholders::_2);
                _dispatcher->registerHandler<BaseMessage>(MType::RSP_RPC, req_cb);
                // 如果启用了服务发现
                if (_isDiscover)
                {
                    auto off_cb=std::bind(&RpcClient::delClient,this,std::placeholders::_1);
                    _discover_client = std::make_shared<DiscovererClient>(ip, port,off_cb);//将删除客户端函数绑定进去 收到下线通知时删除指定客户端
                }
                // 没有启用服务发现 始终使用一个服务器
                else
                {
                    auto dis_cb = std::bind(&Dispatcher::onMessage, _dispatcher.get(), std::placeholders::_1, std::placeholders::_2);
                    _client = ClientFactory::create(ip, port);
                    _client->setMessageCallback(dis_cb);
                    _client->connect();
                }
            }
            // 同步
            bool call(const std::string method, const Json::Value &params, Json::Value &result)
            {
                BaseClient::ptr client = getClient(method);
                if (client.get() == nullptr)
                {
                    return false;
                }
                _caller->call(client->connection(), method, params, result);
                return true;
            }
            // 异步
            bool call(const std::string method, const Json::Value &params, RpcCaller::JsonAsyncResponse &result)
            {
                BaseClient::ptr client = getClient(method);
                if (client.get() == nullptr)
                {
                    return false;
                }
                _caller->call(client->connection(), method, params, result);
                return true;
            }
            // 回调
            bool call(const std::string method, const Json::Value &params, const RpcCaller::JsonResponseCallBack &cb)
            {
                BaseClient::ptr client = getClient(method);
                if (client.get() == nullptr)
                {
                    return false;
                }
                _caller->call(client->connection(), method, params, cb);
                return true;
            }

        private:
            BaseClient::ptr newClient(const Address &host)
            {
                auto message_cb = std::bind(&Dispatcher::onMessage, _dispatcher.get(),
                                            std::placeholders::_1, std::placeholders::_2);
                auto client = ClientFactory::create(host.first, host.second);
                client->setMessageCallback(message_cb);
                client->connect();
                addClient(host, client); // 加入客户端管理
                return client;
            }
            BaseClient::ptr getClient(const Address &host)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _clients.find(host);
                if (it == _clients.end())
                {
                    ELOG("未找到当前服务所提供的主机");
                    return BaseClient::ptr();
                }
                return it->second;
            }
            BaseClient::ptr getClient(const std::string &method) // 通过服务发现者客户端找到主机
            {
                BaseClient::ptr client;
                // 开启了服务发现
                if (_isDiscover)
                {
                    Address host;
                    bool ret = _discover_client->serviceDiscover(method, host); // 获得提供方法的host信息
                    if (ret == false)
                    {
                        ELOG("当前 %s 服务，没有找到服务提供者！", method.c_str());
                        return BaseClient::ptr();
                    }
                    client = getClient(host); // 查看是否已经建立过这个主机的客户端连接了
                    // 没有则新建连接
                    if (client == nullptr)
                    {
                        client = newClient(host);
                    }
                }
                // 没开启始终使用一个客户端
                else
                {
                    client = _client;
                }
                return client;
            }
            bool addClient(const Address &host, BaseClient::ptr client)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _clients.insert(std::make_pair(host, client));
                return true;
            }
            void delClient(const Address &host)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _clients.erase(host);
                DLOG("删除了连接ip为%s,port为%d的服务器",host.first.c_str(),host.second);
            }

        private:
            bool _isDiscover;
            Requestor::ptr _requestor;
            DiscovererClient::ptr _discover_client;
            RpcCaller::ptr _caller;
            Dispatcher::ptr _dispatcher;
            BaseClient::ptr _client;
            std::mutex _mutex;
            std::unordered_map<Address, BaseClient::ptr, AddressHash> _clients; // 用于保存长链接的服务器 //短链接的缺点是异步调用时 不知何时该关闭服务器连接不好控制
        };
        class TopicClient
        {
        public:
            using ptr=std::shared_ptr<TopicClient>;
        public:
            TopicClient(const std::string ip,int port)
            :_requestor(std::make_shared<Requestor>()),
            _dispatcher(std::make_shared<Dispatcher>()),
            _topic(std::make_shared<TopicManager>(_requestor))
            {
                auto req_cb = std::bind(&Requestor::onMessage, _requestor.get(), std::placeholders::_1, std::placeholders::_2);
                auto rsp_cb = std::bind(&TopicManager::onPublish, _topic.get(), std::placeholders::_1, std::placeholders::_2); // 接收到上下线通知的处理
                _dispatcher->registerHandler<BaseMessage>(MType::RSP_TOPIC, req_cb);
                _dispatcher->registerHandler<TopicRequest>(MType::REQ_TOPIC, rsp_cb); 

                auto dis_cb = std::bind(&Dispatcher::onMessage, _dispatcher.get(), std::placeholders::_1, std::placeholders::_2);
                _client = ClientFactory::create(ip, port);
                _client->setMessageCallback(dis_cb);
                _client->connect();
            }
             bool create(const std::string& tname)
            {
                return _topic->create(_client->connection(),tname);
            }
            bool remove(const std::string& tname)
            {
                return _topic->remove(_client->connection(),tname);
                
            }
            bool subscribe(const std::string& tname,const TopicManager::SubCallback& cb)
            {
                return _topic->subscribe(_client->connection(),tname,cb);
                
            }
            bool cancel(const std::string& tname)
            {
                return _topic->cancel(_client->connection(),tname);
                
            }
            bool publish(const std::string&tname,const std::string&msg)
            {
                return _topic->publish(_client->connection(),tname,msg);
            }
            void shutdown()
            {
                _client->shutdown();
            }
        private:
            Requestor::ptr _requestor;
            TopicManager::ptr _topic;
            Dispatcher::ptr _dispatcher;
            BaseClient::ptr _client;
        };
    }
}